=== block A (HR:40) ===
DEST="$HOME/Elsewhere-saved"; IMG="$HOME/Desktop/Elsewhere-saved.dmg"; MARK="$HOME/Elsewhere-saved.VERIFIED"
ew_path() { o=$(ls -ld "$1" 2>&1); r=$?; if [ $r -eq 0 ]; then echo "STILL THERE: $1"; else case "$o" in *"No such file or directory"*) echo "gone: $1";; *) echo "NOT READ: $1 ($o)";; esac; fi; }
ew_launch() { $3 launchctl print "$1" >/dev/null 2>&1; r=$?; case $r in 0) echo "STILL THERE: $2 (loaded)";; 113) echo "gone: $2";; *) echo "NOT READ: $2 (launchctl said $r)";; esac; }
ew_proc() { o=$(ps -A -o pid=,comm= 2>&1) || { echo "NOT READ: the list of running programs"; return 1; }; m=$(printf '%s\n' "$o" | grep -F "/Applications/Elsewhere.app/"); if [ -n "$m" ]; then echo "STILL THERE: the app is running"; printf '%s\n' "$m"; else echo "gone: the app is not running"; fi; }
ew_key() { security find-generic-password -s "$1" >/dev/null 2>&1; r=$?; case $r in 0) echo "STILL THERE: saved item $1";; 44) echo "gone: saved item $1";; *) echo "NOT READ: saved item $1 (status $r)";; esac; }
ew_ext() { o=$(systemextensionsctl list 2>&1); r=$?; if [ $r -ne 0 ]; then echo "NOT READ: system extensions (status $r)"; return 1; fi; case "$o" in *"extension(s)"*) ;; *) echo "NOT READ: system extensions (no count line)"; return 1;; esac; x=$(printf '%s\n' "$o" | grep -F com.leematulis.elsewhere); if [ -z "$x" ]; then echo "gone: system extension"; elif printf '%s\n' "$x" | grep -q "waiting to uninstall on reboot"; then echo "RESTART NEEDED: the system extension finishes leaving at the next restart"; else echo "STILL THERE: system extension"; printf '%s\n' "$x"; fi; }
ew_vpn() { o=$(scutil --nc list 2>&1); r=$?; if [ $r -ne 0 ]; then echo "NOT READ: the VPN list (status $r)"; return 1; fi; case "$o" in *"network connection services"*) ;; *) echo "NOT READ: the VPN list (no heading)"; return 1;; esac; if printf '%s\n' "$o" | grep -qi elsewhere; then echo "STILL THERE: a VPN entry names Elsewhere"; printf '%s\n' "$o" | grep -i elsewhere; else echo "gone: VPN entries"; fi; }
ew_btm() { o=$(sudo sfltool dumpbtm 2>&1); r=$?; if [ $r -ne 0 ] || [ -z "$o" ]; then echo "NOT READ: login and background items (status $r)"; return 1; fi; if printf '%s\n' "$o" | grep -qi com.leematulis.elsewhere; then echo "STILL THERE: a login or background item names Elsewhere"; else echo "gone: login and background items name no Elsewhere"; fi; }
ew_same() { o=$($3 diff -r "$1" "$2" 2>&1); r=$?; if [ $r -eq 0 ] && [ -z "$o" ]; then echo "SAME: $1"; else echo "DIFFERS or NOT READ: $1 (status $r)"; printf '%s\n' "$o" | head -n 5; return 1; fi; }
ew_keep() { o=$($3 ls -ld "$1" 2>&1); r=$?; if [ $r -ne 0 ]; then case "$o" in *"No such file or directory"*) echo "no source (it never existed): $1"; return 0;; *) echo "NOT READ: $1 ($o)"; return 1;; esac; fi; $3 cp -Rp "$1" "$DEST/$2" || { echo "COPY FAILED: $1"; return 1; }; [ -z "$3" ] || $3 chown -R "$(id -u)" "$DEST/$2" || { echo "COPY FAILED: could not hand the copy of $1 to her account"; return 1; }; ew_same "$1" "$DEST/$2" $3; }
ew_ok() { [ -f "$MARK" ] || { echo "REFUSED: the copies are not verified at Lee's end"; return 1; }; }
ew_rm() { ew_ok || return 1; if $2 test -L "$1"; then echo "REFUSED (a link): $1"; elif $2 test -e "$1"; then $2 rm -rf -- "$1" && echo "removed: $1"; else echo "not there: $1"; fi; }
ew_rmf() { ew_ok || return 1; if $2 test -L "$1"; then echo "REFUSED (a link): $1"; elif $2 test -f "$1"; then $2 rm -f -- "$1" && echo "removed: $1"; elif $2 test -e "$1"; then echo "REFUSED (not a regular file): $1"; else echo "not there: $1"; fi; }
EW_WHOLE=$(printf '%s\n' '<dictionary> {' 'ExceptionsList : <array> {' '}' '}' 'ExcludeSimpleHostnames : 0' 'FTPEnable : 0' 'HTTPEnable : 0' 'HTTPSEnable : 0' 'ProxyAutoConfigEnable : 1' 'ProxyAutoDiscoveryEnable : 0' 'SOCKSEnable : 0' | LC_ALL=C sort | tr '\n' '|')
ew_dict() { xs=$(printf 'list Setup:/Network/Service/[^/]+\n' | scutil 2>&1) || return 1; for xi in $(printf '%s\n' "$xs" | sed -n 's|.*Setup:/Network/Service/\([^/ ]*\)$|\1|p'); do xn=$(printf 'show Setup:/Network/Service/%s\n' "$xi" | scutil 2>&1 | sed -n 's/^ *UserDefinedName : //p'); if [ "$xn" = "$1" ]; then printf 'show Setup:/Network/Service/%s/Proxies\n' "$xi" | scutil 2>&1; return; fi; done; return 1; }
ew_extra() { xx=""; for xk in getwebproxy getsecurewebproxy getsocksfirewallproxy; do xo=$(networksetup -$xk "$1" 2>&1); case "$xo" in *"Enabled: No"*) ;; *"Enabled: Yes"*) xx="$xx $xk=ON";; *) xx="$xx $xk=NOT-READ";; esac; done; xb=$(networksetup -getproxybypassdomains "$1" 2>&1); case "$xb" in "There aren't any bypass domains set"*) ;; *) xx="$xx bypass=SET-or-NOT-READ";; esac; xz=$(ew_dict "$1" | sed 's/^ *//' | grep -v '^ProxyAutoConfigURLString' | LC_ALL=C sort | tr '\n' '|'); [ "$xz" = "$EW_WHOLE" ] || xx="$xx stored-fields-or-two-switches=DIFFER-or-NOT-READ"; if [ -z "$xx" ]; then echo "    WHOLE: every stored field, every address and port, and both switches at the foot of the screen are as Elsewhere wrote them"; else echo "    NOT WHOLE (changed after Elsewhere, or not read; an unread field counts as changed):$xx"; fi; }
ew_proxy() {
  NL=$'\n'
  OPEN="function FindProxyForURL(url,host){${NL}function ends(s,x){return s.length>=x.length&&s.substring(s.length-x.length)===x;}${NL}host=String(host).toLowerCase();"
  list=$(networksetup -listallnetworkservices 2>&1)
  case "$list" in "An asterisk"*) ;; *) echo "NOT READ: the list of network services"; return 1;; esac
  printf '%s\n' "$list" | tail -n +2 | sed 's/^\*//' | while IFS= read -r s; do
    [ -n "$s" ] || continue
    o=$(networksetup -getautoproxyurl "$s" 2>&1); r=$?
    case "$o" in *"URL:"*"Enabled:"*) [ $r -eq 0 ] || { echo "NOT READ: [$s] automatic proxy (status $r)"; continue; };; *) echo "NOT READ: [$s] automatic proxy"; continue;; esac
    url=$(printf '%s\n' "$o" | sed -n 's/^URL:[[:space:]]*//p' | head -n 1)
    en=$(printf '%s\n' "$o" | sed -n 's/^Enabled:[[:space:]]*//p' | head -n 1)
    case "$url" in
      ''|'(null)') kind=none;;
      http://*|https://*|file://*) kind=other;;
      "data:application/x-ns-proxy-autoconfig;base64,"*) got=$(printf '%s' "${url#*,}" | base64 -D 2>/dev/null | head -n 3); if [ "$got" = "$OPEN" ]; then kind=ours; else kind=odd; fi;;
      *) kind=odd;;
    esac
    case "$kind:$en" in
      none:*) echo "gone: [$s] no automatic proxy address";;
      other:*) echo "left alone: [$s] an automatic proxy that is not Elsewhere's (switched $en)";;
      ours:Yes) echo "STILL THERE: [$s] Elsewhere's automatic proxy is ON"; ew_extra "$s";;
      ours:*) echo "STILL THERE: [$s] Elsewhere's address is still stored (switched off)"; ew_extra "$s";;
      *) echo "LOOK: [$s] an automatic proxy address this reader does not recognise (switched $en); write it down and leave it on";;
    esac
  done
}
echo "readers ready"

=== block 1 (HR:97) ===
echo "--- proxies"; ew_proxy
echo "--- app"; ew_proc
echo "--- helper"; ew_launch system/com.leematulis.elsewhere.private.proxy-helper "helper" sudo
echo "--- sites agent"; ew_launch "gui/$(id -u)/com.leematulis.elsewhere.private.sites-agent" "sites agent"
echo "--- extension"; ew_ext
echo "--- VPN entries"; ew_vpn
echo "--- login and background items"; ew_btm
echo "--- sites wallet"; ew_path "$HOME/Library/Application Support/ElsewhereSites"
echo "--- provider wallet"; ew_path "$HOME/Library/Application Support/ElsewhereProvider"
echo "--- identity keys"; ew_key com.leematulis.elsewhere.private.assistant; ew_key com.leematulis.elsewhere.private.follow-recovery

=== block 2a (HR:118) ===
launchctl bootout "gui/$(id -u)/com.leematulis.elsewhere.private.sites-agent"
sudo launchctl bootout system/com.leematulis.elsewhere.private.proxy-helper
echo "--- check"; ew_proc; ew_launch "gui/$(id -u)/com.leematulis.elsewhere.private.sites-agent" "sites agent"; ew_launch system/com.leematulis.elsewhere.private.proxy-helper "helper" sudo

=== block 2b (HR:128) ===
if [ -e "$DEST" ] || [ -L "$DEST" ] || [ -e "$IMG" ] || [ -L "$IMG" ] || [ -e "$MARK" ] || [ -L "$MARK" ]; then echo "STOP: a folder, locked file or marker of that name is already there; it is not touched"; else mkdir -m 700 "$DEST" && echo "folder made, owner-only: $DEST"; fi

=== block 2c (HR:134) ===
BAD=0
ew_keep "$HOME/Library/Application Support/ElsewhereSites" sites-wallet || BAD=1
ew_keep "$HOME/Library/Application Support/ElsewhereProvider" provider-wallet || BAD=1
ew_keep "/Library/Application Support/Elsewhere" root-folder sudo || BAD=1
ew_keep "$HOME/Library/Group Containers/2CL959JP97.group.com.leematulis.elsewhere.private" group-container || BAD=1
if [ $BAD -eq 0 ]; then echo "COPIES CHECKED"; else echo "STOP: a copy is not verified; nothing will be deleted"; fi
du -sh "$DEST"

=== block 2d (HR:148) ===
[ "${BAD:-1}" = 0 ] && hdiutil create -srcfolder "$DEST" -volname Elsewhere-saved -encryption AES-256 -format UDZO -o "$IMG"; echo "hdiutil exit: $?"; ls -lh "$IMG"

=== block 2e (HR:156) ===
shasum -a 256 "$IMG"

=== block 2g (HR:166) ===
[ -f "$IMG" ] && [ -d "$DEST" ] && touch "$MARK" && echo "COPIES VERIFIED"

=== block 3b (HR:187) ===
J="$DEST/root-folder/ProxyHelper/journal.plist"
sc=$(plutil -extract schema raw -o - "$J" 2>&1); n=$(plutil -extract entries raw -o - "$J" 2>&1 | grep -c .); ids=$(plutil -p "$J" 2>&1 | sed -n 's/^    "\([0-9A-Fa-f-]\{36\}\)" => {$/\1/p'); c=$(printf '%s\n' "$ids" | grep -c .)
case "$sc" in 1|2) ;; *) echo "UNKNOWN: this is not a readable journal (schema read: $sc)"; ids="";; esac
[ "$n" = "$c" ] || { echo "UNKNOWN: the journal's entries could not all be listed ($n expected, $c found)"; ids=""; }
[ "$n" = 0 ] && echo "NO ENTRY: a readable journal that records no service"
printf '%s\n' "$ids" | while IFS= read -r id; do
  [ -n "$id" ] || continue
  echo "== service $id"
  [ "$(plutil -extract "entries.$id.serviceID" raw -o - "$J" 2>&1)" = "$id" ] || { echo "UNKNOWN: that entry is not identified as $id"; continue; }
  itf=$(plutil -extract "entries.$id.interface" raw -o - "$J" 2>&1); [ -n "$itf" ] && [ "$(plutil -type "entries.$id.interface" "$J" 2>&1)" = string ] || { echo "UNKNOWN: its interface was not read"; continue; }
  echo "interface: $itf"
  [ "$(plutil -type "entries.$id.original" "$J" 2>&1)" = dictionary ] || { echo "UNKNOWN: its record of the earlier value was not read"; continue; }
  t=$(plutil -type "entries.$id.original.plist" "$J" 2>&1)
  case "$t" in
    data) p=$(plutil -extract "entries.$id.original.plist" raw -o - "$J" 2>&1); d=$(printf '%s' "$p" | base64 -D 2>/dev/null | plutil -p - 2>&1); case "$d" in "{"*) echo "earlier Proxies value:"; printf '%s\n' "$d";; *) echo "UNKNOWN: the earlier value did not decode";; esac;;
    *"No value at that key path"*) echo "NO PROXIES VALUE BEFORE ELSEWHERE: this entry is read and identified, and records that the service had none (everything off, lists empty)";;
    *) echo "UNKNOWN: the earlier value was not read ($t)";;
  esac
done

=== block 4a (HR:220) ===
ew_ok && echo "VERIFIED: you may go on"

=== block 4b (HR:233) ===
ew_rm "/Library/Application Support/Elsewhere" sudo
ew_rm "/Library/Application Support/ElsewhereSitesIPC" sudo
ew_rm "/Library/Logs/Elsewhere" sudo
ew_rm "$HOME/Library/Application Support/ElsewhereSites"
ew_rm "$HOME/Library/Application Support/ElsewhereProvider"
ew_rm "$HOME/Library/Group Containers/2CL959JP97.group.com.leematulis.elsewhere.private"
ew_rm "$HOME/Library/Caches/com.leematulis.elsewhere.private"
ew_rm "$HOME/Library/WebKit/com.leematulis.elsewhere.private"
ew_rm "$HOME/Library/HTTPStorages/com.leematulis.elsewhere.private"
ew_ok && defaults delete com.leematulis.elsewhere.private
ew_ok && security delete-generic-password -s com.leematulis.elsewhere.private.assistant
ew_ok && security delete-generic-password -s com.leematulis.elsewhere.private.follow-recovery
ew_rmf "$IMG"
for n in sites-wallet provider-wallet root-folder group-container; do ew_rm "$DEST/$n"; done
ew_ok && { rmdir "$DEST" && echo "removed: $DEST" || echo "NOT REMOVED: $DEST holds something this run did not put there; nothing more is deleted from it"; }

=== block 5 (HR:259) ===
echo "--- files"
for p in "/Applications/Elsewhere.app" "/Library/Application Support/Elsewhere" "/Library/Application Support/ElsewhereSitesIPC" "/Library/Logs/Elsewhere" "$HOME/Library/Application Support/ElsewhereSites" "$HOME/Library/Application Support/ElsewhereProvider" "$HOME/Library/Group Containers/2CL959JP97.group.com.leematulis.elsewhere.private" "$HOME/Library/Caches/com.leematulis.elsewhere.private" "$HOME/Library/WebKit/com.leematulis.elsewhere.private" "$HOME/Library/HTTPStorages/com.leematulis.elsewhere.private" "$HOME/Library/Preferences/com.leematulis.elsewhere.private.plist" "$DEST" "$IMG"; do ew_path "$p"; done
echo "--- Trash"; t=$(ls -1 "$HOME/.Trash" 2>&1) && { if printf '%s\n' "$t" | grep -qi '^Elsewhere'; then echo "STILL THERE: an Elsewhere item is in the Trash"; else echo "gone: nothing named Elsewhere in the Trash"; fi; } || echo "NOT READ: the Trash ($t)"
echo "--- running"; ew_proc
echo "--- helper"; ew_launch system/com.leematulis.elsewhere.private.proxy-helper "helper" sudo
echo "--- sites agent"; ew_launch "gui/$(id -u)/com.leematulis.elsewhere.private.sites-agent" "sites agent"
echo "--- extension"; ew_ext
echo "--- VPN entries"; ew_vpn
echo "--- login and background items"; ew_btm
sudo grep -q com.leematulis.elsewhere /Library/Preferences/com.apple.networkextension.plist; r=$?; case $r in 0) echo "STILL THERE: network settings still name Elsewhere";; 1) echo "gone: network settings name no Elsewhere";; *) echo "NOT READ: the network settings file (status $r)";; esac
echo "--- every service's automatic proxy"; ew_proxy
echo "--- saved items"; ew_key com.leematulis.elsewhere.private.assistant; ew_key com.leematulis.elsewhere.private.follow-recovery

=== block 5b (HR:287) ===
ew_rmf "$MARK"
echo "--- last"; ew_path "$MARK"; ew_path "$DEST"; ew_path "$IMG"

=== block 6 (HR:301) ===
echo "PIN  PATH" | shasum -a 256 -c -
